﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using Microsoft.Win32;
using System.Diagnostics;
using System.Threading.Tasks;
using System.Threading;
using Mengsk.ERP.Orders.TDOrderInterfaces;
using Mengsk.ERP.Database;
using Mengsk.ERP.Orders;

namespace Mengsk.ERP.OrderSync.OrderSyncCore
{
    class ERPOrderSyncManager
    {
        private static readonly string CACHE_DIR = System.IO.Path.Combine(new FileInfo(typeof(ERPOrderSyncManager).Assembly.Location).DirectoryName, "Data");
        private static readonly string CACHE_PATH = CACHE_DIR + "\\ERPOrderSync";
        private const string KEY_PATH = "SOFTWARE\\Mengsk\\ERP";
        private const string KEY_NAME = "ERPOrderSyncLastTime";

        private static ERPOrderSyncManager instance = new ERPOrderSyncManager();

        public static ERPOrderSyncManager Instance { get { return instance; } }

        private ERPOrderSyncCache erpOrderSyncCache = null;
        private ManualResetEvent stopEvent = new ManualResetEvent(false);
        private bool isStop = false;
        private Task downloadOrdersTask = null;
        private TDOrderInterfaceBase[] tdOrderInfaces = null;

        public void Start()
        {
            if (File.Exists(CACHE_PATH))
            {
                using (FileStream fs = new FileStream(CACHE_PATH, FileMode.Open))
                {
                    BinaryFormatter bf = new BinaryFormatter();
                    erpOrderSyncCache = bf.Deserialize(fs) as ERPOrderSyncCache;
                }
            }
            else
            {
                this.erpOrderSyncCache = new ERPOrderSyncCache();
                Microsoft.Win32.RegistryKey key = Microsoft.Win32.RegistryKey.OpenBaseKey(Microsoft.Win32.RegistryHive.CurrentUser, Microsoft.Win32.RegistryView.Registry32);
                RegistryKey erpkey = key.OpenSubKey(KEY_PATH);
                if (erpkey != null)
                {
                    string value = erpkey.GetValue(KEY_NAME).ToString();
                    this.erpOrderSyncCache.LastSyncTime = DateTime.Parse(value);
                }
            }

            if (this.erpOrderSyncCache.LastSyncTime == DateTime.MinValue)
            {
                this.erpOrderSyncCache.LastSyncTime = new DateTime(1999, 1, 1);
            }
            this.tdOrderInfaces = TDOrderInterfaceBase.LoadOrderManagers();
            this.stopEvent.Reset();
            this.downloadOrdersTask = Task.Factory.StartNew(Sync);
        }

        void OrderInsertDownloading(object sender, OrderDownloadEventArgs e)
        {
            Console.WriteLine(e.Shop + "  " + DateTime.Now + " 创建时间" + e.Order.CreateTime + "  " + e.CurrentCount + "  / " + e.Total);
            try
            {
                DBHelper.Instance.Insert("", "Order", e.Order, false, "Items");
                foreach (var item in e.Order.Items)
                {
                    DBHelper.Instance.Insert("", "OrderItem", item, false);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

        void OrderUpdateDownloading(object sender, OrderDownloadEventArgs e)
        {
            int ret = DBHelper.Instance.Update("", OrderManager.TABLE_ORDER, string.Format("POPID='{0}'", e.Order.POPID), null, e.Order, true, "State", "SellerComment", "Flag","PPCOD");
            Console.WriteLine(e.Shop + "  " + (ret == 0 ? "未更新" : "已经更新") + e.Order.CreateTime + " " + e.Order.Name + "  " + e.CurrentCount + "/" + e.Total);
        }

        private void SaveState()
        {
            System.IO.Directory.CreateDirectory(CACHE_DIR);
            using (FileStream fs = new FileStream(CACHE_PATH, FileMode.Create))
            {
                BinaryFormatter bf = new BinaryFormatter();
                bf.Serialize(fs, this.erpOrderSyncCache);
            }
            Microsoft.Win32.RegistryKey key = Microsoft.Win32.RegistryKey.OpenBaseKey(Microsoft.Win32.RegistryHive.CurrentUser, Microsoft.Win32.RegistryView.Registry32);
            RegistryKey erpkey = key.OpenSubKey(KEY_PATH, true);
            if (erpkey == null)
            {
                erpkey = key.CreateSubKey(KEY_PATH);
            }
            erpkey.SetValue(KEY_NAME, this.erpOrderSyncCache.LastSyncTime.ToString("yyyy-MM-dd HH:mm:ss"), RegistryValueKind.String);
        }

        public void Stop()
        {
            this.SaveState();
            this.stopEvent.Set();
        }

        private void Sync()
        {
            while (this.isStop == false)
            {
                try
                {
                    if (this.isStop == false)
                    {
                        this.DownloadOrder();
                    }

                    if (this.isStop == false)
                    {
                        this.SyncOrderState();
                    }

                    ////第天0点更新物流信息
                    //if (hasUpdateDelivery == false || DateTime.Now.Hour == 0)
                    //{
                    //    this.SyncDeliveryEx();
                    //    hasUpdateDelivery = true;
                    //}
                    break;
                }
                catch (Exception ex)
                {
                    Debug.WriteLine(ex.Message);
                }
            }
        }

        private void DownloadOrder()
        {
            OrderDownloadArgs args = new OrderDownloadArgs
            {
                StartTime = DateTime.Now.AddDays(-3),
                EndTime = DateTime.Now.AddMinutes(10),
                RaiseEvents = true,
                DownLoadItems = true,
                DwonloadItemsImage = true,
            };

            try
            {
                Console.Title = "下载订单";

                foreach (var td in this.tdOrderInfaces)
                {
                    td.OrderDownloading += new EventHandler<OrderDownloadEventArgs>(OrderInsertDownloading);
                }
                args.StartTime = this.erpOrderSyncCache.LastSyncTime;
                if (args.StartTime != DateTime.MinValue)
                {
                    args.StartTime = args.StartTime.AddMinutes(-2);
                }
                args.EndTime = DateTime.Now.AddMinutes(3);
                foreach (var tdOrderInterface in this.tdOrderInfaces)
                {
                    tdOrderInterface.DownloadOrders(args);
                }
                this.erpOrderSyncCache.LastSyncTime = args.EndTime;
                this.SaveState();
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.Message);
            }
            finally
            {
                foreach (var td in this.tdOrderInfaces)
                {
                    td.OrderDownloading -= new EventHandler<OrderDownloadEventArgs>(OrderInsertDownloading);
                }
            }
        }

        private static object updateLock = new object();

        private void WriteMessage(Order order, int number, int total, string appendMessage, bool isError)
        {
            string shop = "";
            if (order.Shop == Shop.PAIPAI_YIMEIER)
            {
                shop = "伊妹儿";
            }
            else if (order.Shop == Shop.WANGGOU_MOSIGE)
            {
                shop = "梦诗姬";
            }
            else if (order.Shop == Shop.WANGGOU_SHANGMEIQI)
            {
                shop = "尚美琦";
            }
            else
            {
                shop = order.Shop.ToString();
            }
            string message = string.Format("{0},{1}/{2},{3},{4},{5},{6},{7} {8}", shop, number, total, order.CreateTime.ToString("yy-MM-dd"), order.Name, order.State, order.DeliveryCompany, order.DeliveryNumber, appendMessage);

            lock (updateLock)
            {
                var item = Console.ForegroundColor;
                if (isError)
                {
                    Console.ForegroundColor = ConsoleColor.Red;
                }
                Console.WriteLine(message);
                Console.ForegroundColor = item;
            }
        }

        private void SyncDelivery(Order[] orders, TDOrderInterfaceBase inter)
        {
            string deliveryCompany = null, deliveryNumber = null;
            int i = 0;
            foreach (var order in orders)
            {
                i++;
                for (int j = 0; j < 4; j++)
                {
                    try
                    {
                        deliveryCompany = "";
                        deliveryNumber = "";
                        inter.GetDeliveryInfo(order.POPID, ref deliveryCompany, ref deliveryNumber);
                        if (string.Compare(order.DeliveryCompany, deliveryCompany, false) != 0 || string.Compare(order.DeliveryNumber, deliveryNumber, true) != 0)
                        {
                            order.DeliveryCompany = deliveryCompany;
                            order.DeliveryNumber = deliveryNumber;
                            order.LastUpdateTimeErp = DateTime.Now;
                            order.Comment = "UpdateDelivery";
                            lock (updateLock)
                            {
                                DBHelper.Instance.Update("", "Order", "POPID='" + order.POPID + "'", null, order, true, "DeliveryCompany", "DeliveryNumber", "LastUpdateTimeErp", "Comment");
                            }
                            WriteMessage(order, i, orders.Length, "已更新", false);
                        }
                        else
                        {
                            WriteMessage(order, i, orders.Length, "未更新", false);
                        }
                        break;
                    }
                    catch (Exception ex)
                    {
                        lock (updateLock)
                        {
                            if (ex.Message.IndexOf("0x75121805", StringComparison.OrdinalIgnoreCase) >= 0)
                            {
                                WriteMessage(order, i, orders.Length, "检查到错误", true);
                            }
                            else
                            {
                                WriteMessage(order, i, orders.Length, "检测到错误，65S后重试", true);
                            }
                            Debug.WriteLine(ex.Message + ex.StackTrace);
                            if (ex.Message.IndexOf("0x75121805", StringComparison.OrdinalIgnoreCase) < 0)
                            {
                                Thread.Sleep(65000);
                            }
                        }
                    }
                }
            }
        }

        public void SyncDeliveryEx()
        {
            Console.Title = "同步物流:" + DateTime.Now;
            string[] states = new string[] { "DS_DEAL_CANCELLED", "DS_WAIT_BUYER_PAY", "STATE_COD_CANCEL", "DS_WAIT_SELLER_DELIVERY", "DS_CLOSED", "STATE_COD_WAIT_SHIP" };
            this.tdOrderInfaces = TDOrderInterfaceBase.AllOrderInterfaces;
            Dictionary<Shop, TDOrderInterfaceBase> inters = this.tdOrderInfaces.ToDictionary(new Func<TDOrderInterfaceBase, Shop>(obj => obj.Shop));
            Order[] orders1 = DBHelper.Instance.Select<Order>("", "Order", "DeliveryNumber='' and money > 5 and [CreateTime]>='" + DateTime.Now.AddDays(-30).ToString("yyyy-MM-dd HH:mm:ss") + "'", null, false, "Items").Where(obj => obj.Money > 10 && (obj.Type == OrderType.TRADE0FF ? (obj.State != "STATE_COD_CANCEL") : obj.State != "DS_WAIT_BUYER_PAY" && obj.State != "DS_DEAL_CANCELLED" && obj.State != "DS_UNKNOWN")).OrderBy(obj => obj.CreateTime).ToArray();
            Order[] orders = orders1.Where(obj => states.FirstOrDefault(ob => obj.State == ob) == null).OrderBy(obj => obj.CreateTime).OrderBy(obj => obj.Shop).ToArray();
            Dictionary<Shop, List<Order>> ordersByGroup = new Dictionary<Shop, List<Order>>();
            foreach (var order in orders)
            {
                if (ordersByGroup.ContainsKey(order.Shop) == false)
                {
                    ordersByGroup.Add(order.Shop, new List<Order>());
                }
                ordersByGroup[order.Shop].Add(order);
            }

            Task[] tasks = new Task[ordersByGroup.Count];
            Shop[] shops = ordersByGroup.Keys.ToArray();
            for (int i = 0; i < tasks.Length; i++)
            {
                Order[] tmpOrders = ordersByGroup[shops[i]].ToArray();
                TDOrderInterfaceBase tmpInter = inters[shops[i]];
                tasks[i] = Task.Factory.StartNew(new Action(() => this.SyncDelivery(tmpOrders, tmpInter)));
            }
            Task.WaitAll(tasks);
            Console.Title = "已经完成:" + DateTime.Now;
        }


        public void SyncOrderState()
        {
            Console.Title = "更新订单:" + DateTime.Now;

            try
            {
                this.tdOrderInfaces = TDOrderInterfaceBase.AllOrderInterfaces;

                foreach (var td in this.tdOrderInfaces)
                {
                    td.OrderDownloading += new EventHandler<OrderDownloadEventArgs>(OrderUpdateDownloading);
                }

                OrderDownloadArgs args = new OrderDownloadArgs
                {
                    StartTime = DateTime.Now.AddDays(-30),
                    EndTime = DateTime.Now.AddMinutes(10),
                    RaiseEvents = true,
                    DownLoadItems = false,
                    DwonloadItemsImage = false,
                };

                foreach (var item in this.tdOrderInfaces)
                {
                    Console.WriteLine(item.Shop + "正在下载订单...");
                    Order[] orders = item.DownloadOrders(args);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            finally
            {
                foreach (var td in this.tdOrderInfaces)
                {
                    td.OrderDownloading -= new EventHandler<OrderDownloadEventArgs>(OrderUpdateDownloading);
                }
            }
        }
    }
}
